package modelewithstatemachine;

import guiwithbananaandhungrymonkeys.GUI;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import lois.Loi;
import lois.LoiExp;


//Faites pas gaffe à cette classe.

public class ManagerWithTaxiWithStateMachinePleaseIWantALongerName {

	public static final int DELAI_APPARITION_MAX = 10;
	private final static int cityRadius = 80;
	private int prochaineApparition;
	private int clientsArrives;
	private int clientsPerdus;
	
	private int nbIter;
	
	private double p = 0.1;
	private double lambda = 0.05;
	private Random loiUni;
	private Loi loiDelai;
	
	private static ArrayList<ClientAroundStateMachineOMGIMSURROUNDED> clients;
	private static ArrayList<ClientAroundStateMachineOMGIMSURROUNDED> enAttente;
	private static ArrayList<TaxiWithStateMachine> taxis;
	
	private GUI gui;
	
	public ManagerWithTaxiWithStateMachinePleaseIWantALongerName() {
		init();
		while(nbIter >= 0) {
			try{
				Thread.currentThread();
				Thread.sleep(500);
	        	this.executerPasDeTemps(1);
	        	this.gui.update();
	        }
	        catch(Exception e){
	        	e.printStackTrace();
	        }
		}
	}
	
	public void init() {
		clientsArrives = 0;
		clientsPerdus = 0;
		nbIter = 500;
		
		loiUni = new Random();
		loiDelai = new LoiExp(lambda);
		
//TODO		prochaineApparition = (int)loiDelai.generer();
		prochaineApparition = 10;
		
		clients = new ArrayList<ClientAroundStateMachineOMGIMSURROUNDED>();
		enAttente = new ArrayList<ClientAroundStateMachineOMGIMSURROUNDED>();
		taxis = new ArrayList<TaxiWithStateMachine>();
		
		taxis.add(new TaxiWithStateMachine(4));
		taxis.add(new TaxiWithStateMachine(6));
		//taxis.add(new TaxiWithStateMachine(8));
		
		gui = new GUI();
	}
	
	public void executerPasDeTemps(int pas) {
		
		ArrayList<ClientAroundStateMachineOMGIMSURROUNDED> clientAEnlever = new ArrayList<ClientAroundStateMachineOMGIMSURROUNDED>();
		
		if(nbIter >= 0) {
			nbIter-=pas;
			prochaineApparition-=pas;
			
			for(ClientAroundStateMachineOMGIMSURROUNDED c : enAttente) {
				c.reduireDelaiAttente();
				if(c.getDelaiAttente() <= 0) {
					clientAEnlever.add(c);
					clientsPerdus++;
					System.out.println("Un client disparait :(");
				}
			}
			
			clients.removeAll(clientAEnlever);
			enAttente.removeAll(clientAEnlever);
			
//			System.out.println("Prochaine apparition : "+prochaineApparition);
			
			// Si il est temps qu'un client apparaisse
			if(prochaineApparition <= 0) {
//TODO				prochaineApparition = (int)loiDelai.generer();
				prochaineApparition = 5;

//TODO		    	int delaiAttente = (int)loiDelai.generer();
		    	int delaiAttente = 50;
		    	ClientAroundStateMachineOMGIMSURROUNDED newClient = new ClientAroundStateMachineOMGIMSURROUNDED(this, delaiAttente, taxis);
		    	clients.add(newClient);
				
		    	// Client dans la liste d'attente
				enAttente.add(newClient);

//				System.out.println("Un Client sauvage apparait !\n Il va de environ (" +
//						(int)rDepart + "," + (int)thetaDepart + ") � environ (" +
//						(int)rDest + "," + (int)thetaDest + "), et attendra " + delaiAttente + " unites de temps.");
				// On lui cherche un taxi
				//boolean found = false;
				/*TaxiWithStateMachine bestTaxi = null;
				double bestTime = Double.POSITIVE_INFINITY;
				// Pour chaque taxi
				for(TaxiWithStateMachine taxi : taxis) {
					// S'il a pas d�ja 2 personnes
					// Et qu'il peut se permettre un d�tour
					if(taxi.accepteOrdres()
							&& taxi.accepteDetour(newClient.getrClient(),
									newClient.getThetaClient())) {
						// Si personne d'autre ne voulait
						// On va d�ja prendre lui
						if(found == false) {
							found = true;
							bestTaxi = taxi;
							bestTime = taxi.getTimeToReach(newClient.getrClient(), newClient.getThetaClient());
						}
						else {
							// S'il est plus rapide que le meilleur
							double taxiTime = taxi.getTimeToReach(newClient.getrClient(), newClient.getThetaClient()); 
							if(taxiTime < bestTime) {
								// On le prend
								bestTime = taxiTime;
								bestTaxi = taxi;
							}
						}
					}
				}*/
				
				
				for(ClientAroundStateMachineOMGIMSURROUNDED c : enAttente) {
					int count = 0;
					
					while(count < c.getSortedTaxis().size() && !c.getSortedTaxis().get(count).chercherClient(c))
						count++;
				}
				
				// Si on n'a trouv� personne
				/*if(!found) {
//					System.out.println("Aucun taxi pour le nouveau");
				}
				// On a trouv� un taxi
				else {
//					System.out.println("On vous envoie un taxi !");
					//On ajoute cet ordre en premier
					newClient.setPrisEnCharge(true);
					bestTaxi.addOrdre(new Ordre(newClient, TypeOrdre.PRENDRE), 0);
				}*/
				
//				System.out.println("Prochaine appariton : "+prochaineApparition);	
			}	
			
			//On regarde si on peut satisfaire des clients en attente
			//TODO : A mettre avant ou apr�s l'apparition de clients
			/*for(ClientAroundStateMachineOMGIMSURROUNDED client : enAttente) {
				if(!client.isPrisEnCharge()) {
					double bestTime = Double.POSITIVE_INFINITY;
					TaxiWithStateMachine bestTaxi = null;
					boolean found = false;

					for(TaxiWithStateMachine taxi : taxis) {
						if(taxi.accepteOrdres()) {
							if(0 == taxi.getOrdres().size()) {
								bestTaxi = taxi;
								bestTime = taxi.getTimeToReach(client.getrClient(), client.getThetaClient());
								found = true;
//								taxi.addOrdre(new Ordre(client, TypeOrdre.PRENDRE), 0);
							}
							else if(1 == taxi.getOrdres().size()) {
								Ordre ordre = taxi.getOrdres().get(0);
								
								//Le taxi ne va chercher un autre que s'il est d�j�
								//en train de d�poser quelqu'un
								if(ordre.getTypeOrdre() == TypeOrdre.DEPOSER) {
									if(taxi.accepteDetour(client.getrClient(), client.getThetaClient())) {
										if(!found) {
											bestTime = taxi.getTimeToReach(client.getrClient(), client.getThetaClient());
											bestTaxi = taxi;
											found = true;
										}
										else {
											double taxiTime = taxi.getTimeToReach(client.getrClient(), client.getThetaClient());
											
											if(taxiTime < bestTime) {
												bestTime = taxiTime;
												bestTaxi = taxi;
											}
										}
									}
								}
							}
						}
					}
					
					if(found) {
						bestTaxi.addOrdre(new Ordre(client, TypeOrdre.PRENDRE), 0);
						client.setPrisEnCharge(true);
					}
				}
			}*/
			
			for(TaxiWithStateMachine taxi : taxis) {
				taxi.update();
			}
		}
	}
	
	public void clientArrive(ClientAroundStateMachineOMGIMSURROUNDED client) {
		clientsArrives++;
	}
	
	public void clientDansTaxi(ClientAroundStateMachineOMGIMSURROUNDED client) {
		clients.remove(client);
	}
	
	public void clientPrisEnCharge(ClientAroundStateMachineOMGIMSURROUNDED client) {
		enAttente.remove(client);
	}
	
	public static void main(String[] args) {
		new ManagerWithTaxiWithStateMachinePleaseIWantALongerName();
	}

	public static List<ClientAroundStateMachineOMGIMSURROUNDED> getClients() {
		return clients;
	}
	
	public static List<ClientAroundStateMachineOMGIMSURROUNDED> getEnAttente() {
		return enAttente;
	}

	public static List<TaxiWithStateMachine> getTaxis() {
		return taxis;
	}
	
	public static int getCityRadius() {
		return cityRadius;
	}
}
